package l1j.server.echo;

import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.Config;
import l1j.server.Thread.GeneralThreadPool;
import l1j.server.encryptions.Encryption;
import l1j.server.server.serverpackets.ServerBasePacket;
import l1j.server.server.utils.StreamUtil;


/**
 * 封包加密管理
 *
 * @author dexc
 *
 */
public class EncryptExecutor {

	private static final Logger _log = Logger.getLogger(EncryptExecutor.class.getName());

	private final ClientThread _client;

	private final OutputStream _out;

	private final PacketSc _scPacket;

	private final Encryption _keys;

	private static final byte[] FIRST_PACKET = {//TODO 3.52C封包
		(byte) 0xf9, (byte) 0xb0, (byte) 0x2a, (byte) 0x73,
		(byte) 0x01, (byte) 0x80, (byte) 0xff, (byte) 0xce,
		(byte) 0xc6, (byte) 0xc1,(byte) 0xfa};

	public EncryptExecutor(final ClientThread client, final OutputStream out) {
		this._client = client;
		this._keys = client.get_keys();
		this._out = new BufferedOutputStream(out);
		this._scPacket = new PacketSc(client, this);
	}
	/**
	 * 往客戶端封包 加密處理
	 *
	 * @param serverBasePacket
	 */
	public void encrypt(final ServerBasePacket packet) {
		try {
			if (packet == null) {
				return;
			}
			synchronized(this) {
				this._scPacket.encrypt(packet);
			}

		} catch (final Exception e) {
			_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);
		}
	}
	public ClientThread get_client() {
		return this._client;
	}

	public OutputStream out() {
		return this._out;
	}

	/**
	 * 送出第一組封包的處理
	 */
	public void outStart() {
		try {
			synchronized(this) {
				if (this._out != null) {
					// TODO 採取亂數取by99團隊
					final String keyHax = Integer.toHexString((int) (Math.random() * 2147483647) + 1);
					final int key = Integer.parseInt(keyHax, 16);
					// TODO 採取亂數取by99團隊
					if(Config.LOGINS_TO_AUTOENTICATION) {
						this._out.write((int)(this._client._authdata & 0xff));
						this._out.write((int)(this._client._authdata >> 8 & 0xff));
						this._out.write((int)(this._client._authdata >> 16 & 0xff));
						this._out.write((int)(this._client._authdata >> 24 & 0xff));
						this._out.flush();
					}
					final byte Bogus = (byte) (FIRST_PACKET.length + 7);
					this._out.write(Bogus & 0xFF);
					this._out.write(Bogus >> 8 & 0xFF);
					this._out.write(OpcodesServer.S_OPCODE_INITPACKET);//TODO 變更 3.52C封包
					this._out.write((byte) (key & 0xFF));
					this._out.write((byte) (key >> 8 & 0xFF));
					this._out.write((byte) (key >> 16 & 0xFF));
					this._out.write((byte) (key >> 24 & 0xFF));

					this._out.write(FIRST_PACKET);
					//					_out.flush();
					//					_out.write(OpcodesClient._firstPacket);

					// 刷新此输出流并强制写出所有缓冲的输出字节。
					this._out.flush();// 清空資料*/
					try {
						this._keys.initKeys(key);

					} catch (final Exception e) {
						this.stop();
						throw new EncryptErrorException("設置加密公式發生異常: " + this._client.getIp(), e);
					}
				}
			}
		} catch (final Exception e) {
			//_log.error(e.getLocalizedMessage(), e);
		}
	}

	public void satrt() {
		GeneralThreadPool.getInstance().schedule(this._scPacket, 0);
	}

	public void stop() {
		try {
			this._scPacket.stop();
				StreamUtil.close(this._out);
		} catch (final Exception e) {
			//_log.error(e.getLocalizedMessage(), e);
		}
	}
}
